查看原文
其他

如何快速使用BERT?

TotoroWang 深度学习这件小事 2022-03-29

来自 | 知乎   作者 | TotoroWang
地址 | https://zhuanlan.zhihu.com/p/112235454
编辑 | 深度学习这件小事公众号
本文仅作交流,如有侵权,请后台联系删除

   前言

由于最近一直在做BERT模型的相关工作,在此记录下快速使用BERT模型的几种常用方式~

   BERT 模型

BERT模型作为目前最强预训练模型,其性能表现在NLP领域刷新的多个记录。虽然BERT在很多领域都取得了 state-of-the-art 的结果,但是,BERT模型的训练是十分困难的,参数量达到惊人的亿级的规模,一般用户是无法完成训练的。庆幸的是,Google开源了多个版本的BERT预训练模型,具体有如下版本:
  • BERT-Large, Uncased (Whole Word Masking)

    • 语言种类:英文

    • 网络结构:24-layer, 1024-hidden, 16-heads

    • 参数规模:340M

  • BERT-Large, Cased (Whole Word Masking)

    • 语言种类:英文

    • 网络结构:24-layer, 1024-hidden, 16-heads

    • 参数规模:340M

  • BERT-Base, Uncased

    • 语言种类:英文

    • 网络结构:12-layer, 768-hidden, 12-heads

    • 参数规模:110M

  • BERT-Large, Uncased

    • 语言种类:英文

    • 网络结构:24-layer, 1024-hidden, 16-heads

    • 参数规模:340M

  • BERT-Base, Cased

    • 语言种类:英文

    • 网络结构:12-layer, 768-hidden, 12-heads

    • 参数规模:110M

  • BERT-Large, Cased

    • 语言种类:英文

    • 网络结构:24-layer, 1024-hidden, 16-heads

    • 参数规模:340M

  • BERT-Base, Multilingual Cased (New, recommended)

    • 语言种类:104 种语言

    • 网络结构:12-layer, 768-hidden, 12-heads

    • 参数规模:110M

  • BERT-Base, Multilingual Uncased (Orig, not recommended)

    • 语言种类:102 种语言、

    • 网络结构:12-layer, 768-hidden, 12-heads

    • 参数规模:110M

  • BERT-Base, Chinese

    • 语言种类:中文

    • 网络结构:12-layer, 768-hidden, 12-heads

    • 参数规模:110M

从上面的版本可以看出,语言主要分为三种:中文、英文和多语言。其中英文和多语言版本还区分:cased 和 uncased,cased 表示区分大小写,uncased 表示不区分大小写。网络结构主要分为两种:Base 和 Large。Base版本相比于Large版本网络规模较小,参数量为110M。中文的预训练模型只有一个版本,是用Base版本的网络结构训练得到。
BERT模型具体的网络结构和原理可阅读论文 BERT ,在此不再赘述。

   BERT 模型的使用

BERT 模型的使用主要有两种用途:
一、当作文本特征提取的工具,类似Word2vec模型一样
二、作为一个可训练的层,后面可接入客制化的网络,做迁移学习

   特征提取工具

作为特征提取的工具,有一种简单的使用方式:bert-as-service
首先,需要安装 server 和 client 两个包:
pip install bert-serving-server # 服务端
pip install bert-serving-client # 客户端
环境要求:Python >= 3.5 Tensorflow >= 1.10
然后,下载 BERT 预训练模型,可以点击上述链接下载,比如我们下载中文版本 BERT 模型BERT-Base, Chinese 。下载完成后,解压到本地某个目录下。
例如:/tmp/chinese_L-12_H-768_A-12/
然后,打开终端,输入以下命令启动服务:
bert-serving-start -model_dir /tmp/chinese_L-12_H-768_A-12/ -num_worker=2
其中,参数 model_dir 设置为解压得到的BERT预训练模型路径,num_worker为进程数。需要说明的是,num_worker 必须小于CPU的核心数或GPU设备数。
最后,编写客户端代码:
from bert_serving.client import BertClient
bc = BertClient()
bc.encode(['龙猫小组真棒', '关注有惊喜', '哈哈'])
对于句子对的编码,可以利用 ||| 符号作为两个句子的分隔符:
bc.encode(['龙猫小组真棒 ||| 关注有惊喜'])
当然,还有一些参数可以自定义设置,以及不同 API 可以使用,详细可参考:bert-as-service
除了 bert-as-service 这种使用方式外,当然也可以利用Tensorflow、Keras等深度学习框架重建 BERT 预训练模型,然后利用重建的BERT模型去获取文本的向量表示。

   Tensorflow 加载 BERT 模型

使用 Tensorflow 加载 BERT 模型,常用的方法有两种:
  • 利用 bert 开源代码

  • 利用 Tensorflow_hub(推荐)

利用 bert 开源代码的好处在于,API 文档很详细,可以使用预训练模型快速进行Fine-tune、文本分类等任务。但是 bert 开源代码是在 Tensorflow 1.11.0 上开发,对于想要使用 Tensorfow 2.0 版本的小伙伴可能不太友好。如果想使 bert 开源代码运行在 Tensorflow 2.0 及以上版本,需要修改一部分源码 (关注专栏,私信我,可以直接获取哦~)
Tensorflow 加载模型的核心代码如下:
import tensorflow as tf
from bert import modeling

tf.compat.v1.disable_eager_execution()

def convert_ckpt_to_saved_model(bert_config, init_checkpoint):
# BERT配置文件
bert_config = modeling.BertConfig.from_json_file(bert_config)

# 创建BERT的输入
input_ids = tf.compat.v1.placeholder(shape=(None, None), dtype=tf.int32, name='input_ids')
input_mask = tf.compat.v1.placeholder(shape=(None, None), dtype=tf.int32, name='input_mask')
segment_ids = tf.compat.v1.placeholder(shape=(None, None), dtype=tf.int32, name='segment_ids')

# 创建BERT模型
model = modeling.BertModel(
config=bert_config,
is_training=True,
input_ids=input_ids,
input_mask=input_mask,
token_type_ids=segment_ids,
use_one_hot_embeddings=False, # 使用TPU时,设置为True,速度会快;使用CPU/GPU时,设置为False,速度会快。
)

# 获取模型中所有的训练参数
tvars = tf.compat.v1.trainable_variables()

# 加载BERT模型
(assigment_map, initialized_variable_names) = modeling.get_assignment_map_from_checkpoint(tvars=tvars, init_checkpoint=init_checkpoint)
tf.compat.v1.train.init_from_checkpoint(init_checkpoint, assigment_map)

# 打印加载模型的参数
tf.compat.v1.logging.info(" **** Trainable Variables ****")
for var in tvars:
init_string = ""
if var.name in initialized_variable_names:
init_string = ", *INIT_FROM_CKPT*"
tf.compat.v1.logging.info(" name = {}, shape = {}{}".format(var.name, var.shape, init_string))

with tf.compat.v1.Session() as sess:
sess.run(tf.compat.v1.global_variables_initializer())
bert_config 为预训练模型中的 bert_config.json 文件路径,init_checkpoint 为 bert_model.ckpt 文件路径。如果想要把模型参数和网络结构保存为更方便部署的 pb 文件,也就是 SavedModel 格式,可以利用如下方法:
builder = tf.compat.v1.saved_model.builder.SavedModelBuilder(saved_model_path)

model_signature = tf.compat.v1.saved_model.signature_def_utils.build_signature_def(
inputs={
"input_ids": tf.compat.v1.saved_model.utils.build_tensor_info(input_ids),
"input_mask": tf.compat.v1.saved_model.utils.build_tensor_info(input_mask),
"segment_ids": tf.compat.v1.saved_model.utils.build_tensor_info(segment_ids)},
outputs={
"pooled_output": tf.compat.v1.saved_model.utils.build_tensor_info(model.pooled_output),
"sequence_output": tf.compat.v1.saved_model.utils.build_tensor_info(model.sequence_output)},
method_name=tf.compat.v1.saved_model.signature_constants.PREDICT_METHOD_NAME)

builder.add_meta_graph_and_variables(
sess,
[tf.saved_model.TRAINING, tf.saved_model.SERVING],
strip_default_attrs=False,
signature_def_map={
tf.compat.v1.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
model_signature})
builder.save()
saved_model_path 为 SavedModel 模型存储路径。
除了上述使用方法外,还有更简单的方式使用 BERT 模型,即使用 Tensorflow_hub,
需要,需要安装 Tensorflow_hub,
pip install tensorflow_hub
然后,下载可供 hub 模块使用的 SavedModel 格式的 BERT 模型,下载链接在这里。
下载完成后,解压至本地,就可以利用如下方法加载模型:
import tensorflow_hub as hub

bert_layer = hub.KerasLayer(BERT_PATH, trainable=True, name='bert_layer')
当然,也可以不下载模型至本地,也可以直接传入模型的 URL 地址,也可以加载模型:
BERT_URL = "https://tfhub.dev/tensorflow/bert_zh_L-12_H-768_A-12/1"
bert_layer = hub.KerasLayer(BERT_URL, trainable=True, name='bert_layer')

   Keras 加载 BERT 模型

Keras 加载 BERT 模型,同样可以利用 Tensorflow_hub 去加载模型作为一个KerasLayer。还有一种方法可以同样方便的加载模型,就是利用 keras_bert ,方法如下:
首先,安装 keras_bert
pip install keras-bert
然后,利用 load_trained_model_from_checkpoint 方法可直接加载 checkpoint 格式的BERT模型
def BertLayer(bert_path, trainable=True, training=False, seq_len=None, name='bert_layer'):

bert_config_path = os.path.join(bert_path, 'bert_config.json')
bert_checkpoint_path = os.path.join(bert_path, 'bert_model.ckpt')

bert_layer = load_trained_model_from_checkpoint(
bert_config_path, bert_checkpoint_path, training=training, seq_len=seq_len)

bert_layer.name = name

for layer in bert_layer.layers:
layer.trainable = trainable

return bert_layer

   后记

本节主要介绍了快速使用 BERT 模型的几种常用方法,方便自己今后查阅,也方便有需求的小伙伴们快速使用 BERT 模型,之后会进一步分享如何使用BERT做具体的NLP任务~


—完—

为您推荐

为什么魂斗罗只有128KB却可以实现那么长的剧情?

GitHub重大更新:在线开发上线,是时候卸载IDE了

有了这个神器,轻松用 Python 写个 App

「最全」实至名归,NumPy 官方早有中文教程

史上最烂的项目:苦撑12年,600多万行代码...

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存